home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 15
/
Aminet 15 - Nov 1996.iso
/
Aminet
/
text
/
hyper
/
hsc_source.lha
/
source
/
hscdepp
/
hscdepp.c
< prev
Wrap
C/C++ Source or Header
|
1996-09-09
|
19KB
|
744 lines
/*
* hscdepp
*
* Dependency generator for hsc-project
*
* Copyright (C) 1996 Thomas Aglassinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*-------------------------------------------------------------------
*
* Author : Thomas Aglassinger (Tommy-Saftwörx)
* Email : agi@giga.or.at, agi@sbox.tu-graz.ac.at
* Address: Lissagasse 12/II/9
* 8020 Graz
* AUSTRIA
*
*-------------------------------------------------------------------
*
* hscdepp/hscdepp.c
*
* updated: 8-Sep-1996
* created: 8-Jul-1996
*/
/* ANSI includes */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ugly includes */
#include "ugly/ustring.h"
#include "ugly/dllist.h"
#include "ugly/expstr.h"
#include "ugly/infile.h"
#include "ugly/uargs.h"
#include "ugly/prginfo.h"
#include "ugly/returncd.h"
/* hsclib includes */
#include "hscprj/document.h"
#include "hscprj/project.h"
/* include revision data */
#include "hscdepp/hscdepp_rev.h"
#ifdef AMIGA
/* AmigaOS version string
* (imported from "hscdepp_rev.h")
*/
static const STRPTR AmigaOS_version = VERSTAG;
#endif
/* prefix for messages */
#define HD ""
#define DHD "*hscdep* "
#define SHIT "*** " /* prefix for total failure */
/* debugging define */
#ifdef DEBUG
#undef DEBUG
#define DEBUG 1
#endif
#ifdef D
#undef D
#endif
#if DEBUG
#define D(x) if (debug) {x;}
#else
#define D(x) {/*nufin*/}
#endif
/* step-sizes for input-file/depency-string */
#define CHUNKSIZE_INPUTFILE (64*1024)
#define CHUNKSIZE_DEPENDSTR (16*1024)
/* default parameters */
#define DEFAULT_PROJECT "hsc.project" /* project-filename */
#define DEFAULT_NAMEALL "all_hsc" /* "all"-rule */
/* size of buffer for fgets() */
#define MAXBUFSIZE 1024
#define STR_DEPENDS_PRECEDE \
"# --- DO NOT MODIFY THIS LINE -- hsc-dependencies precede ---\n"
#define STR_DEPENDS_FOLLOW \
"# --- DO NOT MODIFY THIS LINE -- hsc-dependencies follow ---\n"
/*
* global vars
*/
static int return_code = RC_FAIL; /* exit code of program */
static STRPTR makefile = NULL;
static STRPTR prjfile = NULL;
static STRPTR nameall = NULL;
static BOOL verbose = FALSE;
static BOOL nobackup = FALSE;
static BOOL notaglines = FALSE;
static BOOL debug = FALSE;
static EXPSTR *lines_precede = NULL;
static EXPSTR *lines_follow = NULL;
static EXPSTR *lines_depend = NULL;
static HSCPRJ *project = NULL;
/*
* cleanup: free all resources
* (called in any case)
*/
static VOID cleanup(VOID)
{
D(fprintf(stderr, "(cleanup)\r"));
del_project(project);
del_estr(lines_precede);
del_estr(lines_follow);
del_estr(lines_depend);
D(fprintf(stderr, " "));
}
static VOID set_return_code(int new_code)
{
if (new_code > return_code)
return_code = new_code;
}
/*
* hsc_nomem_handler
*
* called from ugly/umalloc, if malloc() did return NULL
*/
static BOOL hscdepp_nomem_handler(size_t size)
{
fputs(SHIT "out of memory\n", stderr);
return_code = RC_FAIL;
exit(return_code);
return (FALSE); /* immediatly abort */
}
VOID msg_corrupt_pf(HSCPRJ * hp, STRPTR reason)
{
fprintf(stderr, "project-file corrupt: %s\n", reason);
}
/*
* show_license
*
* display short description of GNU GPL
*/
static VOID show_license(VOID)
{
STRPTR license = /* the usual boring text */
"\nThis program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n";
fprintf(stderr, license);
}
/*
* args_ok
*
* prepare args, check & parse user args, display error and
* help message if neccessary
*
* result: TRUE, if all args ok and no request for HELP or
* LICENSE has been detected
*/
static BOOL args_ok(int argc, char *argv[])
{
struct arglist *hscdepp_args; /* argument structure */
BOOL arg_help = FALSE;
BOOL arg_license = FALSE;
BOOL ok = FALSE;
/* create arg-table */
hscdepp_args = prepare_args
("HSCDEPP_ARGS",
"FILE/T", &makefile, "makefile to update",
"PRJFILE/T/K", &prjfile, "project file",
"NAMEALL/T/K", &nameall, "name for `all_hsc' rule",
"VERBOSE/S", &verbose, "verbose output",
"NOBACKUP/S", &nobackup, "do not backup makefile",
"NOTAGLINES/S", ¬aglines, "do not write taglines",
"-DEBUG/S", &debug, "enable debugging output",
"HELP=?=-h/S", &arg_help, "display this text",
"LICENSE/S", &arg_license, "display license",
NULL);
ok = (hscdepp_args != NULL);
/* set & test args */
if (ok)
{
ok = set_args(argc, argv, hscdepp_args);
/* display argument error message */
if (!ok)
{
pargerr();
set_return_code(RC_ERROR);
}
else if (arg_help || arg_license)
{
/*
* display help or license text
*/
fprintf_prginfo(stderr);
if (arg_help)
fprintf_arghelp(stderr, hscdepp_args);
else
show_license();
set_return_code(RC_WARN);
ok = FALSE;
}
else
{
/* auto-enable verbose in debug-mode */
if (debug)
verbose = TRUE;
/* display copyright in verbose-mode */
if (verbose)
fprintf_prginfo(stderr);
/* set default-parameters if neccessary */
if (!prjfile)
{
prjfile = DEFAULT_PROJECT;
if (verbose)
fprintf(stderr, HD "%s: using default project-file\n",
prjfile);
}
if (!nameall)
{
nameall = DEFAULT_NAMEALL;
}
/* debugging control output */
D(
if (makefile)
{
fprintf(stderr, DHD "makefile=`%s'\n", makefile);
fprintf(stderr, DHD "makefile=DEFAULT\n");
fprintf(stderr, DHD "prjfile =`%s'\n", prjfile);
fprintf(stderr, DHD "nameall =`%s'\n", nameall);
}
);
}
/* release mem used by args */
free_args(hscdepp_args);
}
else
{
/* only for developer */
D(fprintf(stderr, SHIT "ArgDef error: %lu\n", prep_error_num));
}
#if 1
return (ok);
#else
return (FALSE); /* for arg-debugging */
#endif
}
/*
* read_makefile
*
* scan for fitting makefile, read all it's data into a list
* of strings, exept those which are between taglines
*/
static BOOL read_makefile(VOID)
{
STRPTR scanfile[] =
{"GNUmakefile", "Makefile", "makefile", NULL};
FILE *file = NULL;
BOOL ok = FALSE;
lines_precede = init_estr(1024);
lines_follow = init_estr(1024);
/*
* open makefile
*/
errno = 0;
if (!makefile)
{
/* scan for makefile */
int i = 0;
D(fprintf(stderr, DHD "scanning makefile\n"));
makefile = scanfile[0];
while (!file && makefile)
{
D(fprintf(stderr, DHD " try `%s'\n", makefile));
file = fopen(makefile, "r");
if (!file)
{
i += 1;
makefile = scanfile[i];
}
}
}
else
{
/* use makefile specified by user */
D(fprintf(stderr, DHD "makefile `%s' specified by user\n", makefile));
file = fopen(makefile, "r");
}
if (!file)
{
if (!makefile)
makefile = "Makefile";
fprintf(stderr, HD "%s: creating new makefile\n", makefile);
ok = TRUE;
}
else
{
static STRARR buf[MAXBUFSIZE]; /* buffer for fgets() */
BOOL found = FALSE; /* flag: tag-line found */
STRPTR line = NULL; /* current line read */
/*
* read Makefile
*/
/* reset error variable */
errno = 0;
/*
* read preceding lines
*/
do
{
line = fgets(buf, MAXBUFSIZE, file);
if (line)
if (!strcmp(line, STR_DEPENDS_FOLLOW))
found = TRUE;
else
app_estr(lines_precede, line);
}
while (!found && !errno && line);
if (errno)
{
fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
set_return_code(RC_ERROR);
}
else if (!line)
{
/* tag-line not found */
if (verbose)
fprintf(stderr, HD "%s: no starting tag-line; "
"appending dependencies\n", makefile);
}
else
{
/*
* skip old dependencies
*/
D(fprintf(stderr, DHD "starting tagline found\n"));
found = FALSE;
do
{
line = fgets(buf, MAXBUFSIZE, file);
if (line)
if (!strcmp(line, STR_DEPENDS_PRECEDE))
found = TRUE;
}
while (!found && !errno && line);
if (errno)
{
fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
set_return_code(RC_ERROR);
}
else if (!line)
{
/* tag-line not found */
if (verbose)
fprintf(stderr, HD "%s: no ending tag-line; "
"appending dependencies\n", makefile);
}
else
{
/*
* read following lines
*/
D(fprintf(stderr, DHD "ending tagline found\n"));
do
{
line = fgets(buf, MAXBUFSIZE, file);
if (line)
app_estr(lines_follow, line);
}
while (!errno && line);
if (errno)
{
fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
set_return_code(RC_ERROR);
}
}
}
if (!errno)
{
if (verbose)
fprintf(stderr, HD "%s: makefile read\n", makefile);
ok = TRUE;
}
/* close makefile */
fclose(file);
}
return (ok);
}
/*
* read_project
*
* read data from project file
*/
static BOOL read_project(VOID)
{
BOOL ok = FALSE;
INFILE *inpf = NULL;
if (verbose)
{
fprintf(stderr, HD "%s: reading..\r", prjfile);
fflush(stderr);
}
/* assign message-callback for corrupt project-file */
project->CB_msg_corrupt_pf = msg_corrupt_pf;
/* read project-file */
errno = 0;
inpf = infopen(prjfile, CHUNKSIZE_INPUTFILE);
if (inpf)
{
if (hsc_project_read_file(project, inpf))
{
if (verbose)
fprintf(stderr, HD "%s: project-file read\n", prjfile);
ok = TRUE;
}
infclose(inpf);
}
if (!ok)
{
fprintf(stderr, HD "error reading `%s'", prjfile);
if (errno)
fprintf(stderr, HD ": %s", strerror(errno));
fprintf(stderr, "\n");
}
return (ok);
}
/*
* update_makefile
*
* create dependency-lines from project-info,
*/
/* append linefeed to dependency-line */
static VOID depline_applf(ULONG * linelen)
{
*linelen = 0;
app_estr(lines_depend, "\n");
}
/* append string to dependency-line */
static VOID depline_appstr(STRPTR s, ULONG * linelen)
{
#define LEADING_BLANKS " "
size_t slen = strlen(s);
/* check if line would become too long after appending
* the current word */
if ((*linelen + slen) >= 75)
{
D(fprintf(stderr, DHD "break line after %lu chars to avoid %lu\n",
*linelen, *linelen + slen));
app_estr(lines_depend, " \\\n");
app_estr(lines_depend, LEADING_BLANKS);
*linelen = strlen(LEADING_BLANKS);
}
app_estrch(lines_depend, ' ');
app_estr(lines_depend, s);
*linelen = *linelen + slen + 1;
}
/*
* update_makefile - main function
*/
static BOOL update_makefile(VOID)
{
BOOL ok = FALSE;
ULONG linelen = 0; /* length of current line */
DLNODE *docnode = dll_first(project->documents);
BOOL bak_ok = TRUE;
lines_depend = init_estr(CHUNKSIZE_DEPENDSTR);
/* append tagline */
if (!notaglines)
app_estr(lines_depend, STR_DEPENDS_FOLLOW);
/* append some header info */
if (!notaglines)
{
#define MAXTIMEBUF 40
time_t now = time(NULL);
STRARR timebuf[MAXTIMEBUF];
if (strftime(timebuf, MAXTIMEBUF, "%A %d-%b-%Y %H:%M:%S",
localtime(&now)))
{
app_estr(lines_depend, "\n# dependencies updated: ");
app_estr(lines_depend, timebuf);
app_estr(lines_depend, "\n\n");
}
}
/*
* append all-rule
*/
if (docnode->data)
{
app_estr(lines_depend, nameall);
app_estr(lines_depend, " :");
linelen = strlen(nameall) + 2;
while (docnode)
{
HSCDOC *document = dln_data(docnode);
depline_appstr(document->docname, &linelen);
docnode = dln_next(docnode);
}
app_estr(lines_depend, "\n\n");
}
/*
* append document data
*/
docnode = dll_first(project->documents);
while (docnode)
{
HSCDOC *document = dln_data(docnode);
DLNODE *incnode = dll_first(document->includes);
D(fprintf(stderr, DHD "document `%s'\n", document->docname));
app_estr(lines_depend, document->docname);
app_estr(lines_depend, " :");
linelen = strlen(document->docname) + 2;
/* dependency for main source */
depline_appstr(document->sourcename, &linelen);
/* dependencies for includes */
while (incnode)
{
HSCINC *include = dln_data(incnode);
depline_appstr(include->name, &linelen);
incnode = dln_next(incnode);
}
/* append linefeed after dependency-list */
app_estr(lines_depend, "\n\n");
docnode = dln_next(docnode);
}
/* append tagline */
if (!notaglines)
app_estr(lines_depend, STR_DEPENDS_PRECEDE);
/*
* create backup
*/
if (!nobackup)
{
EXPSTR *makefile_bak = init_estr(32); /* filename for backup */
set_estr(makefile_bak, makefile);
app_estr(makefile_bak, ".bak");
/* remove old backup */
remove(estr2str(makefile_bak));
/* rename old makefile to backup
*
* NOTE: if this fails, this can also be because
* there wasn't any earlier copy, therefor no
* error-message is displayed */
if (!rename(makefile, estr2str(makefile_bak)))
{
if (verbose)
fprintf(stderr, HD "%s: backup created\n",
estr2str(makefile_bak));
}
del_estr(makefile_bak);
}
/*
* write makefile
*/
if (bak_ok)
{
FILE *outf = NULL;
/* open output makefile */
errno = 0;
outf = fopen(makefile, "w");
if (outf)
{
/* write output */
errno = 0;
fprintf(outf, "%s%s%s",
estr2str(lines_precede), estr2str(lines_depend),
estr2str(lines_follow));
if (errno)
{
/* write error */
fprintf(stderr, "error writing to `%s': %s\n",
makefile, strerror(errno));
}
else
ok = TRUE;
/* close output */
fclose(outf);
}
else
{
/* error opening output */
fprintf(stderr, "error opening `%s' for output: %s\n",
makefile, strerror(errno));
}
}
return (ok);
}
/*
*
* main function
*
*/
int main(int argc, char *argv[])
{
#ifndef BETA
#define BETA 0
#endif
/* set program information */
set_prginfo("hscdepp", "Tommy-Saftwörx", VERSION, REVISION, BETA,
"hsc dependency procreator",
"Freeware, type `hscdepp LICENSE' for details.");
#if DEBUG
/* display a memory tracking report */
/* at end of execution */
atexit(atexit_uglymemory);
#endif
/* install nomem-handler */
ugly_nomem_handler = hscdepp_nomem_handler;
/* use cleanup() as additional exit func */
if (!atexit(cleanup))
{
/*
* main procedure
*/
return_code = RC_OK;
project = new_project();
if (project
&& args_ok(argc, argv)
&& read_makefile()
&& read_project()
&& update_makefile()
)
{
if (verbose)
{
fprintf(stderr, HD "%s: updated using `%s'\n",
makefile, prjfile);
}
return_code = RC_OK;
}
}
else
{
fputs(SHIT "atexit() failed ", stderr);
}
return (return_code);
}